﻿//========================================================= 
/**@file H003AppJsonCmdDriver.h
 * @brief H003应用Json报文通信
 * 
 * @date 2017-02-17   09:53:22
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_H003APPJSONCMDDRIVER_H_
#define _LIBZHOUYB_H003APPJSONCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../../wrapper/jsoncpp/jsoncpp_extractor.h"
using zhou_yb::wrapper::jsoncpp_extractor::JsonArgParser;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// Json数据报文组包器
class AppJsonEditor
{
protected:
    //----------------------------------------------------- 
    string _module;
    string _cmd;
    string _router;
    string _message;
    string _type;
    Json::Value _arg;
    //----------------------------------------------------- 
public:
    //----------------------------------------------------- 
    /// 处理指令的模块名称(类名)
    inline AppJsonEditor& Module(const string& module)
    {
        _module = module;
        return (*this);
    }
    /// 发送的指令名称
    inline AppJsonEditor& Command(const string& cmd)
    {
        _cmd = cmd;
        return (*this);
    }
    /// 路由(对象名)
    inline AppJsonEditor& Router(const string& router)
    {
        _router = router;
        return (*this);
    }
    /// 路由消息
    inline AppJsonEditor& Message(const string& msg)
    {
        _message = msg;
        return (*this);
    }
    /// 消息列别
    inline AppJsonEditor& Type(const string& type)
    {
        _type = type;
        return (*this);
    }
    /// 添加参数
    AppJsonEditor& Arg(const IStringArguments& arg)
    {
        IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
        while(enumer.MoveNext())
        {
            _arg[enumer.Current().Key] = enumer.Current().Value;
        }
        return (*this);
    }
    /// 添加参数
    AppJsonEditor& Arg(const string& sArg)
    {
        JsonArgParser parser;
        StringArguments arg;
        parser.Parse(ByteArray(sArg.c_str(), sArg.length()), arg);
        return Arg(arg);
    }
    /// 添加数据
    template<class T>
    AppJsonEditor& Arg(const string& key, const T& val)
    {
        _arg[key] = ArgConvert::ToString<T>(val);
        return (*this);
    }
    /// 获取指令Json数据,返回添加的Arg数目
    size_t ToJsonString(ByteBuilder& json)
    {
        Json::Value root;
        list_t<Json::Value>::iterator itr;
        
        if(_arg.size() > 0) root["Arg"] = _arg;
        if(_cmd.length() > 0) root["CMD"] = _cmd;
        if(_module.length() > 0) root["Module"] = _module;
        if(_router.length() > 0) root["Router"] = _router;
        if(_message.length() > 0) root["MSG"] = _message;
        if(_type.length() > 0) root["Type"] = _type;

        Json::FastWriter writer;
        string jsonstr = writer.write(root);
        // -1去掉末尾的 0x0A 换行符
        json.Append(ByteArray(jsonstr.c_str(), jsonstr.length() - 1));

        return _arg.size();
    }
    /// 清空参数
    inline void Clear()
    {
        _arg.clear();
    }
    /// 重置
    void Reset()
    {
        _module = "";
        _cmd = "";
        _router = "";
        _message = "";
        _type = "";
        Clear();
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
/// 应用层命令交互驱动
class AppJsonCmdDriver :
    public CommonCmdDriver,
    public BaseDevAdapterBehavior<IInteractiveTrans>,
    public InterruptBehavior
{
protected:
    //----------------------------------------------------- 
    /// 发送缓冲区
    ByteBuilder _sendBuff;
    /// 接收缓冲区
    ByteBuilder _recvBuff;
    /// 指令过滤器
    CommandFilter _cmdFilter;
    //----------------------------------------------------- 
    /// 发送JSON
    bool _SendJSON(AppJsonEditor& editor)
    {
        _sendBuff.Clear();
        _sendBuff += 0x02;

        editor.ToJsonString(_sendBuff);
        LOGGER(_log << "Send JSON:<" << _sendBuff.SubArray(1).GetString() << ">\n");
        _sendBuff += 0x03;
        ASSERT_FuncErr(_cmdFilter.Write(_sendBuff), DeviceError::SendErr);
        return true;
    }
    /// 接收JSON
    bool _RecvJSON()
    {
        _recvBuff.Clear();
        ASSERT_FuncErr(_cmdFilter.Read(_recvBuff), DeviceError::RecvErr);
        return true;
    }
    /// 解析报文数据
    bool _ParseJSON(IStringArguments& rlt)
    {
        JsonArgParser parser;
        _recvBuff.RemoveTail();
        ByteArray jsonBuff = _recvBuff.SubArray(1);
        LOGGER(_log << "Recv JSON:<" << jsonBuff.GetString() << ">\n");
        parser.Parse(jsonBuff, rlt);

        string sErrCode;
        ASSERT_FuncErr(rlt.Get("CODE", sErrCode), DeviceError::RecvFormatErr);
        uint errCode = ArgConvert::FromString<uint>(sErrCode);
        ASSERT_FuncErr(DeviceError::IsSuccess(errCode), DeviceError::DevReturnErr);
        return true;
    }
    /// 交互数据
    bool _TransmitJSON(AppJsonEditor& editor, IStringArguments& rlt)
    {
        LOG_FUNC_NAME();
        return _SendJSON(editor) && _RecvJSON() && _ParseJSON(rlt);
    }
    /// 交互数据
    inline bool _TransmitJSON(AppJsonEditor& editor)
    {
        StringArguments rlt;
        return _TransmitJSON(editor, rlt);
    }
    //----------------------------------------------------- 
public:
    //----------------------------------------------------- 
    /**
     * @brief 组反射调用命令参数
     * @date 2017-12-06 16:52
     *
     * @description 调用ICommand:boolean Module::Run(JSONObject arg, JSONObject rlt)接口
     * 
     * @param [in] sModule 需要调用的模块(类名)
     * @param [in] sCmd 需要调用的命令(需要反射的类成员函数)
     * @param [in] cmdArg 调用命令的参数
     * @param [out] arg 生成的命令参数
     */
    static IStringArguments& MakeCall(const char* sModule, const char* sCmd, const IStringArguments& cmdArg, StringArguments& arg)
    {
        JsonArgParser parser;
        arg.Put("Module", _strput(sModule));
        arg.Put("Router", "JSON");
        arg.Put("MSG", "Reflect");
        arg.Put("Type", "CMD");
        arg.Put("CMD", _strput(sCmd));
        ByteBuilder sArg(16);
        parser.ToString(cmdArg, sArg);
        arg.Put("Arg", sArg.GetString());
        return arg;
    }
    //----------------------------------------------------- 
    /**
     * @brief 构造反射调用的参数
     * @date 2018-05-19 14:41
     * 
     * @param [in] module 需要反射的模块
     * @param [in] cmd 需要反射调用的接口
     * @param [out] editor 生成的调用参数
     */
    static inline AppJsonEditor& MakeCall(const string& module, const string& cmd, AppJsonEditor& editor)
    {
        editor.Module(module).Command(cmd).Router("JSON").Message("Reflect").Type("CMD");
        return editor;
    }
    /// 构造派发消息的调用参数
    static inline AppJsonEditor& MakePost(const string& router, const string& msg, AppJsonEditor& editor)
    {
        editor.Router(router).Message(msg).Type("Call");
        return editor;
    }
    /// 构造派发消息获取数据的调用参数
    static inline AppJsonEditor& MakeMSG(const string& router, const string& msg, AppJsonEditor& editor)
    {
        editor.Router(router).Message(msg).Type("MSG");
        return editor;
    }
    //----------------------------------------------------- 
    AppJsonEditor& CopyArgToEditor(const IStringArguments& arg, AppJsonEditor& editor, const string& exceptKeys)
    {
        string sArg;
        if(!arg.Get("Arg", sArg))
        {
            IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
            list_t<string> keys;
            StringHelper::Split(exceptKeys.c_str(), keys, '|');
            while(enumer.MoveNext())
            {
                IStringArguments::ArgType current = enumer.Current();
                ByteArray cKey(current.Key.c_str(), current.Key.length());
                bool isContains = false;
                for(list_t<string>::iterator itr = keys.begin();!isContains && itr != keys.end(); ++itr)
                {
                    ByteArray eKey(itr->c_str(), itr->length());
                    isContains = StringConvert::Compare(cKey, eKey);
                    if(isContains)
                        break;
                }
                if(!isContains)
                {
                    editor.Arg(current.Key, current.Value);
                }
            }
        }
        else
        {
            editor.Arg(sArg);
        }
        return editor;
    }
    //----------------------------------------------------- 
    AppJsonCmdDriver() : CommonCmdDriver()
    {
        _cmdFilter.SetReadTX(0x02, 0x03);

        _RegisteCMD(AppJsonCmdDriver, OnPost);
        _RegisteCMD(AppJsonCmdDriver, OnMSG);
        _RegisteCMD(AppJsonCmdDriver, OnCall);

        _RegisteAdapterCMD(AppJsonCmdDriver);
        _RegisteCancelCMD(AppJsonCmdDriver);
    }
    LC_CMD_CANCEL(*this);
    LC_CMD_ADAPTER_INVOKE(IInteractiveTrans, _cmdFilter);
    /**
     * @brief 交换Json报文数据
     * @date 2017-05-01 22:32
     * 
     * @param [in] editor 需要发送的Json报文
     * @param [out] rlt 获取到的Json字段
     */
    bool Transmit(AppJsonEditor& editor, IStringArguments& rlt)
    {
        LOG_FUNC_NAME();
        ASSERT_Device();
        return _logRetValue(_TransmitJSON(editor, rlt));
    }
    /**
     * @brief 派发消息接口
     * @date 2018-05-19 14:44
     * 
     * @param [in] Router 需要派发的消息路由结点名称
     * @param [in] MSG : 需要派发的消息名称
     * @param [in] Arg : 远程调用时的参数(没有该参数则枚举其他非Router和MSG的字段作为参数)
     */
    LC_CMD_METHOD(OnPost)
    {
        AppJsonEditor editor;
        CopyArgToEditor(arg, editor, "Router|MSG");
        MakePost(arg["Router"].To<string>(), arg["MSG"].To<string>(), editor);
        return _TransmitJSON(editor, rlt);
    }
    /**
     * @brief 调用消息获取数据接口
     * @date 2018-05-19 14:44
     * 
     * @param [in] Router 需要派发的消息路由结点名称
     * @param [in] MSG : 需要派发的消息名称
     * @param [in] Arg : 远程调用时的参数(没有该参数则枚举其他非Router和MSG的字段作为参数)
     */
    LC_CMD_METHOD(OnMSG)
    {
        AppJsonEditor editor;
        CopyArgToEditor(arg, editor, "Router|MSG");
        MakeMSG(arg["Router"].To<string>(), arg["MSG"].To<string>(), editor);
        return _TransmitJSON(editor, rlt);
    }
    /**
     * @brief 远程调用接口(反射)
     * @date 2017-04-30 17:38
     * 
     * @param [in] CMD : string 需要调用的命令
     * @param [in] Arg : string 调用时的参数(一般为Json格式字符串,没有该参数则枚举其他非CMD和Module字段作为参数)
     * @param [in] Module : string 需要调用的模块名称(Java类名)
     * 
     * @retval Rlt : string 调用后返回的参数(字段)
     */
    LC_CMD_METHOD(OnCall)
    {
        AppJsonEditor editor;
        CopyArgToEditor(arg, editor, "CMD|Module");
        MakeCall(arg["Module"].To<string>(), arg["CMD"].To<string>(), editor);
        return _TransmitJSON(editor, rlt);
    }
};
//--------------------------------------------------------- 
/// H003应用层命令交互驱动
class H003AppJsonCmdDriver : public AppJsonCmdDriver
{
public:
    H003AppJsonCmdDriver() : AppJsonCmdDriver()
    {
        _RegisteCMD(H003AppJsonCmdDriver, OnRemoteCall);
        _RegisteCMD(H003AppJsonCmdDriver, BthSetting);
        _RegisteCMD(H003AppJsonCmdDriver, PullFile);
        _RegisteCMD(H003AppJsonCmdDriver, PushFile);
        _RegisteCMD(H003AppJsonCmdDriver, SwitchToPage);
        _RegisteCMD(H003AppJsonCmdDriver, EleSign);
        _RegisteCMD(H003AppJsonCmdDriver, Speak);
        _RegisteCMD(H003AppJsonCmdDriver, LocalStore);
        _RegisteCMD(H003AppJsonCmdDriver, BthWhiteList);
        _RegisteCMD(H003AppJsonCmdDriver, UsbWhiteList);
        _RegisteCMD(H003AppJsonCmdDriver, DisplayPassword);
    }
    /**
     * @brief 远程调用
     * @date 2017-11-13 22:05
     *
     * @param [in] RemoteCMD : string 远程调用的命令
     * @param [in] RemoteArg : string 远程调用时的参数(没有该参数则枚举其他非RemoteCMD和RemouteArg的字段作为参数)
     *
     * @retval Rlt : string 调用后返回的参数(字段)
     */
    LC_CMD_METHOD(OnRemoteCall)
    {
        AppJsonEditor editor;
        string sArg;
        if(!arg.Get("RemoteArg", sArg))
        {
            IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
            while(enumer.MoveNext())
            {
                IStringArguments::ArgType current = enumer.Current();
                if(StringConvert::Compare(current.Key.c_str(), "RemoteCMD") ||
                    StringConvert::Compare(current.Key.c_str(), "RemoteArg"))
                {
                    continue;
                }
                editor.Arg(current.Key, current.Value);
            }
        }
        else
        {
            editor.Arg(sArg);
        }
        editor.Arg("Cmd", arg["RemoteCMD"].To<string>());
        MakeCall("JNI", "OnCall", editor);
        return _TransmitJSON(editor, rlt);
    }
    /**
     * @brief 蓝牙信息
     * @date 2017-02-20 20:33
     * 
     * @param [in] Name : string 需要设置的蓝牙名称
     */
    LC_CMD_METHOD(BthSetting)
    {
        string sName;
        if(!arg.Get("Name", sName))
            return true;
        AppJsonEditor editor;
        MakeCall("BTH", "SetName", editor).Arg("Name", sName);
        return _TransmitJSON(editor);
    }
    /**
     * @brief 拉取文件
     * @date 2017-02-20 17:47
     * 
     * @param [in] SrcFile : string 需要拉取的文件名称
     * @param [in] DstFile : string 存放的文件名称
     * @param [in] BlockSize : uint [default:8] 每次读取文件的数据块大小(以K为单位)
     * @param [in] RetryCount : uint [default:3] 传输失败时的最大尝试次数
     * @param [in] IsVerifyMD5 : bool [default:false] 是否校验MD5值
     * 
     * @retval MD5 : hex 文件的MD5值
     */
    LC_CMD_METHOD(PullFile)
    {
        string srcFile;
        string dstFile;

        if(!arg.Get("SrcFile", srcFile))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[SrcFile]");
            return false;
        }
        if(!arg.Get("DstFile", dstFile))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[DstFile]");
            return false;
        }

        AppJsonEditor editor;
        MakeCall("FILE", "Open", editor)
            .Arg("Name", srcFile);
        // 打开文件
        StringArguments jsonRlt;
        ASSERT_FuncInfo(_TransmitJSON(editor, jsonRlt), "打开目标文件失败");

        size_t filesize = jsonRlt["Size"].To<size_t>();
        ofstream fout;
        string dstTmpFile = dstFile;
        dstTmpFile += ".download";
        fout.open(dstTmpFile.c_str(), ios::out | ios::binary);
        ASSERT_FuncErrInfo(!fout.fail(), DeviceError::DevOpenErr, "创建下载文件失败");

        // 读取数据
        size_t blocksize = FILE_K(arg["BlockSize"].To<size_t>(8));
        uint retryCount = arg["RetryCount"].To<uint>(3);
        size_t offset = 0;

        editor.Clear();
        editor.Command("Read");

        ByteBuilder buff(blocksize);
        bool bOK = false;
        bool bRead = false;
        while(true)
        {
            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                break;
            }
            editor.Clear();
            editor.Arg("Offset", offset).Arg("Length", blocksize).Arg("IsBase64", true);

            jsonRlt.Clear();
            bRead = _TransmitJSON(editor, jsonRlt);
            if(!bRead)
            {
                editor.Clear();
                editor.Arg("Offset", offset)
                    .Arg("Length", blocksize)
                    .Arg("IsBase64", true);

                uint i = 0;
                for(i = 0; i < retryCount;++i)
                {
                    jsonRlt.Clear();
                    if(_TransmitJSON(editor, jsonRlt))
                        break;
                }
                if(i > retryCount)
                {
                    _logErr(DeviceError::RecvErr, "接收文件数据失败");
                    FolderHelper::EraseFile(dstTmpFile.c_str());
                    break;
                }
            }
            size_t rlen = jsonRlt["Length"].To<size_t>(0);
            // 文件读取失败
            if(rlen < 1)
                break;
            offset += rlen;

            buff.Clear();
            Base64_Provider::Decode(jsonRlt["Data"].Value.c_str(), buff);
            fout.write(buff.GetString(), buff.GetLength());

            // 文件已经全部读取完
            if(offset >= filesize)
            {
                bOK = true;
                break;
            }
        }
        fout.close();

        // 关闭文件
        editor.Clear();
        jsonRlt.Clear();
        editor.Command("Close");
        _TransmitJSON(editor, jsonRlt);

        if(!bOK)
        {
            _logErr(DeviceError::OperatorErr, "文件下载失败");
            return false;
        }

        // 如果存在和目的文件相同的文件则直接删除
        FolderHelper::EraseFile(dstFile.c_str());
        ASSERT_FuncErrInfo(rename(dstTmpFile.c_str(), dstFile.c_str()) == 0,
            DeviceError::OperatorErr, "重命名临时文件失败");

        string sMD5 = jsonRlt["MD5"].To<string>();
        rlt.Put("MD5", sMD5);
        if(!arg["IsVerifyMD5"].To<bool>(false))
            return true;
        ASSERT_FuncErrInfo(sMD5.length() > 0, DeviceError::RecvFormatErr, "目标文件MD5错误");

        ByteBuilder fileMD5(16);
        MD5_Provider md5Provider;
        IHashAlgorithm::File(md5Provider, dstFile.c_str(), fileMD5);
        string sFileMD5 = ArgConvert::ToString(fileMD5);
        rlt.Put("FileMD5", sFileMD5);

        LOGGER(_log << "文件MD5:<" << sMD5 << ">\n";
        _log << "计算MD5:<" << sFileMD5 << ">\n");

        ByteBuilder md5(16);
        DevCommand::FromAscii(sMD5.c_str(), md5);
        ASSERT_FuncErrInfo(fileMD5.IsEqual(md5), DeviceError::DevVerifyErr, "文件MD5校验失败");
        return true;
    }
    /**
     * @brief 写入文件
     * @date 2017-03-20 17:47
     * 
     * @param [in] SrcFile : string 需要写入的文件名称
     * @param [in] DstFile : string 存放的文件名称
     * @param [in] BlockSize : uint [default:8] 每次读取文件的数据块大小(以K为单位)
     * @param [in] RetryCount : uint [default:3] 传输失败时的最大尝试次数
     * @param [in] IsVerifyMD5 : bool [default:false] 是否强制校验MD5值
     * 
     * @retval MD5 : hex 文件的MD5值
     */
    LC_CMD_METHOD(PushFile)
    {
        string srcFile;
        string dstFile;

        if(!arg.Get("SrcFile", srcFile))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[SrcFile]");
            return false;
        }
        if(!arg.Get("DstFile", dstFile))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[DstFile]");
            return false;
        }

        AppJsonEditor editor;
        MakeCall("FILE", "Create", editor)
            .Arg("Name", dstFile);
        // 打开文件
        StringArguments jsonRlt;
        ASSERT_FuncInfo(_TransmitJSON(editor, jsonRlt), "创建目标文件失败");

        ifstream fin;
        fin.open(srcFile.c_str(), ios::in | ios::binary);
        ASSERT_FuncErrInfo(!fin.fail(), DeviceError::DevOpenErr, "打开上传文件失败");

        size_t blocksize = FILE_K(arg["BlockSize"].To<size_t>(8));
        uint retryCount = arg["RetryCount"].To<uint>(3);

        ByteBuilder buff(blocksize);
        ByteBuilder base64Buff(blocksize);
        size_t offset = 0;
        char* pBuff = ctype_cast(char*)(buff.GetBuffer());
        size_t len = 0;
        bool bOK = false;
        MD5_Provider md5Provider;
        while(true)
        {
            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                break;
            }

            fin.read(pBuff, blocksize);
            len = static_cast<size_t>(fin.gcount());
            ByteArray rBuff(pBuff, len);
            md5Provider.Update(rBuff);

            base64Buff.Clear();
            Base64_Provider::Encode(rBuff, base64Buff);

            editor.Clear();
            editor.Arg("Data", base64Buff.GetString())
                .Arg("Offset", offset)
                .Arg("Length", len)
                .Arg("IsBase64", true);
            editor.Command("Write");

            uint i = 0;
            for(i = 0; i < retryCount;++i)
            {
                jsonRlt.Clear();
                if(_TransmitJSON(editor, jsonRlt))
                    break;
            }
            if(i > retryCount)
            {
                _logErr(DeviceError::SendErr, "发送文件数据失败");
                break;
            }
            // 文件已经读取完
            if(len < 1 || fin.eof())
            {
                bOK = true;
                break;
            }

            offset += len;
        }
        fin.close();

        // 关闭文件
        editor.Clear();
        jsonRlt.Clear();
        editor.Command("Close");
        _TransmitJSON(editor, jsonRlt);

        if(!bOK)
        {
            _logErr(DeviceError::OperatorErr, "文件拉取失败");
            return false;
        }

        string sMD5 = jsonRlt["MD5"].To<string>();
        rlt.Put("MD5", sMD5);
        if(!arg["IsVerifyMD5"].To<bool>(false))
            return true;
        ASSERT_FuncErrInfo(sMD5.length() > 0, DeviceError::RecvFormatErr, "下载文件MD5错误");

        ByteBuilder fileMD5(16);
        md5Provider.Final(fileMD5);
        string sFileMD5 = ArgConvert::ToString(fileMD5);

        LOGGER(_log << "文件MD5:<" << sMD5 << ">\n";
        _log << "计算MD5:<" << sFileMD5 << ">\n");

        ByteBuilder md5(16);
        DevCommand::FromAscii(sMD5.c_str(), md5);
        ASSERT_FuncErrInfo(fileMD5.IsEqual(md5), DeviceError::DevVerifyErr, "文件MD5校验失败");
        return true;
    }
    /**
     * @brief 切换页面
     * @date 2017-02-20 18:19
     * 
     * @param [in] Animation : string 需要切换的界面ID(动画文件名)
     * - 预置ID:
     *  - Finger : 指纹
     *  - Contact : 接触
     *  - Contactless : 非接
     *  - ID : 身份证
     *  - MAG : 磁条
     *  - PinPad : 密码键盘
     *  - Signature : 签名
     * .
     * 
     * @param [in] Timeout : uint [default:0] 页面显示的超时时间(ms)
     */
    LC_CMD_METHOD(SwitchToPage)
    {
        string animation;
        if(!arg.Get("Animation", animation))
            return true;
        AppJsonEditor editor;
        MakeCall("AMIMATION", "", editor).Arg(arg);
        return _TransmitJSON(editor);
    }
    /**
     * @brief 播放广告
     * @date 2017-12-26 16:12
     *
     * @param [in] Dir : string 需要播放广告的目录
     * @param [in] IntervalMs : uint [default:3000] 图片播放间隔(ms)
     */
    LC_CMD_METHOD(SwitchToAD)
    {
        AppJsonEditor editor;
        editor.Arg(arg).Arg("Animation", "")
            .Module("AnimationHandler")
            .Command("Open")
            .Router("ANIMATION");
        return _TransmitJSON(editor);
    }
    /**
     * @brief 播放语音
     * @date 2017-02-20 20:33
     * 
     * @param [in] Speak : string 需要播放的语音
     */
    LC_CMD_METHOD(Speak)
    {
        string speak;
        if(!arg.Get("Speak", speak))
            return true;
        AppJsonEditor editor;
        MakeCall("TTS", "Speak", editor).Arg("Speak", speak);
        return _TransmitJSON(editor);
    }
    /**
     * @brief 电子签名
     * @date 2017-02-21 15:57
     * 
     * @param [in] Timeout : uint [default:10min] 等待签名的时间(ms)
     * @param [in] Interval : uint [default:500] 轮询签名结果的超时时间(ms)
     * @param [in] BmpFile : string 签名图片保存路径
     * @param [in] SignFile : string 签名轨迹保存路径
     */
    LC_CMD_METHOD(EleSign)
    {
        uint timeoutMs = arg["Timeout"].To<uint>(10 * 60 * 1000);
        uint intervalMs = arg["Interval"].To<uint>(DEV_CANCEL_TIMEOUT);

        AppJsonEditor editor;
        MakePost("Service", "StartActivity", editor)
            .Arg("Activity", "Sign")
            .Arg("Package", "com.hardware.service.signhandler");
        ASSERT_Func(_TransmitJSON(editor));

        const char STATUS_BUSY[] = "Busy";
        const char STATUS_OK[] = "OK";
        const char STATUS_CANCEL[] = "Cancel";

        StringArguments jsonRlt;
        editor.Reset();
        MakeMSG("Sign", "IsSigned", editor);
        //　等待签名数据
        Timer timer;
        bool bOK = false;
        while(true)
        {
            if(timer.Elapsed() >= timeoutMs)
            {
                _logErr(DeviceError::WaitTimeOutErr, "等待签名数据超时");
                break;
            }

            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                break;
            }

            jsonRlt.Clear();
            if(_TransmitJSON(editor, jsonRlt))
            {
                string status = jsonRlt["Status"].To<string>(STATUS_BUSY);
                if(StringConvert::Compare(status.c_str(), STATUS_OK, true))
                {
                    bOK = true;
                    break;
                }
                else if(StringConvert::Compare(status.c_str(), STATUS_CANCEL, true))
                {
                    _logErr(DeviceError::OperatorStatusErr, "用户取消签名");
                    break;
                }
            }
            Timer::Wait(intervalMs);
        }
        // 通讯正常才发关闭指令
        if(_lasterr != DeviceError::RecvErr)
        {
            // 返回起始界面
            editor.Reset();
            MakePost("Service", "StartActivity", editor)
                .Arg("Activity", "Main");
            _TransmitJSON(editor);
        }
        return bOK;
    }
    /**
     * @brief 读写配置文件
     * @date 2017-05-09 13:57
     * 
     * @param [in] File : string 需要读写的配置文件名称
     * @param [in] Storage : string [default:Null] 写入时的Json字符串
     * 
     * @retval Storage : string 读取时的Json字符串
     */
    LC_CMD_METHOD(LocalStore)
    {
        string file;
        if(!arg.Get("File", file))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[File]");
            return false;
        }
        string storage;
        bool isWrite = arg.Get("Storage", storage);
        AppJsonEditor editor;
        string sCmd = isWrite ? "Write" : "Read";
        MakeCall("FILE", isWrite ? "Create" : "Open", editor)
            .Arg("Name", arg["File"].To<string>());
        // 打开文件
        StringArguments jsonRlt;
        ASSERT_FuncInfo(_TransmitJSON(editor, jsonRlt), "打开配置文件失败");
        size_t length = jsonRlt["Size"].To<size_t>();
        editor.Clear();
        editor.Arg("Data", storage)
            .Arg("IsBase64", false)
            .Arg("Length", length)
            .Command(sCmd);
        jsonRlt.Clear();
        if(!_TransmitJSON(editor, jsonRlt))
        {
            _logErr(DeviceError::RecvErr, "操作配置文件失败");
            editor.Clear();
            editor.Command("Close");
            return false;
        }
        const string& sRlt = (isWrite ? storage : jsonRlt["Data"].To<string>());
        rlt.Put("Storage", sRlt);
        // 关闭文件
        editor.Clear();
        editor.Command("Close");
        _TransmitJSON(editor);
        return true;
    }
    /**
     * @brief 蓝牙白名单设置
     * @date 2017-12-25 13:49
     *
     * @param [in] Mode : string 需要操作的模式
     * - 模式:
     *  - Select : 查找 0
     *  - Append : 增加 1
     *  - Delete : 删除 2
     * .
     *
     * @param [in] Name : string 需要设置的名称
     * @param [in] Address : string 需要设置的地址
     *
     * @param [in] File : string 蓝牙配置文件目录
     *
     * @retval Count : size_t 修改的行数
     *
     * @retval Name : string 操作过程中的名称
     * @retval Address : string 操作过程中的地址
     */
    LC_CMD_METHOD(BthWhiteList)
    {
        const char NAME_KEY[] = "Name";
        const char ADR_KEY[] = "Address";

        StringArguments jsonArg;
        StringArguments jsonRlt;
        string file = arg["File"].To<string>();
        jsonArg.Put("File", file);
        bool bOK = LocalStore(jsonArg, jsonRlt);
        Json::Value root;
        if(bOK)
        {
            string sJson = jsonRlt["Storage"].To<string>();
            if(JsonArgParser::ToJson(sJson.c_str(), root))
            {
                ASSERT_FuncErrInfo(root.isArray(), DeviceError::ArgFormatErr, "Json不是数组形式");
            }
        }
        else
        {
            // 文件不存在则新建一个文件
            jsonArg.Put("Storage", "");
            bOK = LocalStore(jsonArg, jsonRlt);
            ASSERT_FuncErr(bOK, DeviceError::OperatorErr);
        }
        string mode = arg["Mode"].To<string>("Select");
        uint nMode = 0;
        if(StringConvert::Compare(mode.c_str(), "Select", true) ||
            StringConvert::Compare(mode.c_str(), "0"))
        {
            nMode = 0;
        }
        else if(StringConvert::Compare(mode.c_str(), "Append", true) ||
            StringConvert::Compare(mode.c_str(), "1"))
        {
            nMode = 1;
        }
        else if(StringConvert::Compare(mode.c_str(), "Delete", true) ||
            StringConvert::Compare(mode.c_str(), "2"))
        {
            nMode = 2;
        }
        
        string name = arg[NAME_KEY].To<string>();
        string adr = arg[ADR_KEY].To<string>();
        size_t count = 0;
        Json::Value bthCfg;
        bool isAppend = true;
        Json::UInt itemCount = root.size();
        for(Json::UInt i = 0;i < itemCount; ++i)
        {
            Json::Value& val = root[i];
            if(val.isMember(NAME_KEY) && val.isMember(ADR_KEY))
            {
                string itemName = JsonArgParser::ToString(val[NAME_KEY]);
                string itemAdr = JsonArgParser::ToString(val[ADR_KEY]);
                bool isContains = StringConvert::Contains(name.c_str(), itemName.c_str(), true) &&
                    StringConvert::Contains(adr.c_str(), itemAdr.c_str(), true);
                // 已经有重复项不需要再添加
                if(isContains)
                {
                    isAppend = false;
                }
                switch(nMode)
                {
                    // Delete
                case 2:
                    if(!isContains)
                    {
                        bthCfg.append(val);
                    }
                    else
                    {
                        ++count;
                        rlt.Put(NAME_KEY, itemName);
                        rlt.Put(ADR_KEY, itemAdr);
                    }
                    break;
                    // Append
                case 1:
                    bthCfg.append(val);
                    break;
                    // Select
                case 0:
                default:
                    if(isContains)
                    {
                        ++count;
                        bthCfg.append(val);

                        rlt.Put(NAME_KEY, itemName);
                        rlt.Put(ADR_KEY, itemAdr);
                    }
                    break;
                }
            }
        }
        if(isAppend)
        {
            Json::Value item;
            item[NAME_KEY] = name;
            item[ADR_KEY] = adr;
            bthCfg.append(item);
            count = 1;

            rlt.Put(NAME_KEY, name);
            rlt.Put(ADR_KEY, adr);
        }
        rlt.Put("Count", ArgConvert::ToString(count));
        // 将配置文件回写到设备中
        Json::FastWriter writer;
        jsonArg.Clear();
        jsonArg.Put("File", file);
        jsonArg.Put("Storage") = writer.write(bthCfg);
        jsonRlt.Clear();
        return LocalStore(jsonArg, jsonRlt);
    }
    /**
     * @brief USB白名单设置
     * @date 2017-12-26 09:32
     *
     * @param [in] IsEnable : bool [default:true] 是否启用
     * 
     * @param [in] Name : string [default:""] 需要设置的设备名称
     * - 值:
     *  - "null" : 清空白名单
     *  - ""     : 将当前USB添加到白名单
     *  - 其他   : 将指定设备添加到白名单
     * .
     * @param [in] VID : hex [default:""] 需要设置的VID
     * @param [in] PID : hex [default:""] 需要设置的PID
     * @param [in] SN : hex [default:""] 需要设置的设备SN
     *
     * @retval IsEnable : 当前设置是否启用USB白名单功能
     *
     * @retval Name : string 白名单中设备的名称(数组)
     * @retval VID : hex 白名单中设备的VID(数组)
     * @retval PID : hex 白名单中设备的PID(数组)
     * @retval SN : hex 白名单中设备的SN(数组)
     *
     * @retval CurrentCount : size_t 当前连接的USB设备数目(数组前N项)
     * @retval Count : size_t USB设备数目
     */
    LC_CMD_METHOD(UsbWhiteList)
    {
        const char USB_KEY[] = "USB";
        const char NAME_KEY[] = "Name";
        const char VID_KEY[] = "VID";
        const char PID_KEY[] = "PID";
        const char SN_KEY[] = "SN";
        const char IS_ENABLE_KEY[] = "IsEnable";
        
        AppJsonEditor editor;
        string sName = arg[NAME_KEY].To<string>("");
        if(!StringConvert::Compare(sName.c_str(), "null", true))
        {
            Json::Value usb;
            Json::Value item;
            if(sName.length() > 0)
            {
                item[NAME_KEY] = sName;
                item[VID_KEY] = arg[VID_KEY].To<string>();
                item[PID_KEY] = arg[PID_KEY].To<string>();
                item[SN_KEY] = arg[SN_KEY].To<string>();
            }
            Json::Value::UInt index = 0;
            usb[index] = item;
            editor.Arg(USB_KEY, JsonArgParser::ToString(usb));
        }

        editor.Arg(IS_ENABLE_KEY, arg[IS_ENABLE_KEY].To<bool>(true))
            .Command("UsbWhite")
            .Module("AndroidDevHandler")
            .Router("DEV");
        StringArguments jsonRlt;
        ASSERT_Func(_TransmitJSON(editor, jsonRlt));
        rlt.Put(IS_ENABLE_KEY, jsonRlt[IS_ENABLE_KEY].Value);
        list_t<string> usblist;
        size_t currentCount = jsonRlt.Get("CurrentUSB", usblist);
        size_t count = 0;
        count += currentCount;
        count += jsonRlt.Get(USB_KEY, usblist);
        JsonArgParser parser;
        list_t<string>::iterator itr;
        for(itr = usblist.begin();itr != usblist.end(); ++itr)
        {
            parser.Parse(itr->c_str(), rlt);
        }
        rlt.Put("CurrentCount", ArgConvert::ToString(currentCount));
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 回显密码
     * @date 2017-07-11 20:52
     * 
     * @param [in] Password : string 需要显示的数据
     */
    LC_CMD_METHOD(DisplayPassword)
    {
        const char PWD_KEY[] = "Password";
        AppJsonEditor editor;
        string password;
        if(arg.Get(PWD_KEY, password))
        {
            editor.Arg(PWD_KEY, password);
        }
        editor.Module("AnimationHandler")
            .Command("Password")
            .Router("ANIMATION");
        return _TransmitJSON(editor);
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_H003APPJSONCMDDRIVER_H_
//========================================================= 